#-*- coding: utf-8 -*

# 此程序为读取超声波测距仪的数据

import serial
from PyQt4 import QtCore
from Myserial import Myserial
import math


class ultralsonic(QtCore.QThread):
    '''
            This class is defined as a ultralsonic modle which can get direct range using the 0xb4/0xbc commd，
        and you can get the range by the formula: S = voice_speed * Time,in other words,this class can get range
        using temperature(by 18B20 sensor) and voice speed.
    '''

    RangeSignal = QtCore.pyqtSignal(float)

    def __init__(self, serial_baud=9600, parent= None):
        super(ultralsonic, self).__init__(parent)

        self.serial_baud = serial_baud
        self.ultralsonic_addr = '\xe8'      # 超声波串口模式寄存器地址
        self.ultralsonic_registor = '\x02'  # 超声波控制寄存器
        # 得到最终的命令 此处最终的命令为测试命令，降噪或者其他命令另外计算
        self.ultralsonic_commd_set = self.ultralsonic_addr + self.ultralsonic_registor
        # 得到超声波设备端口号
        self.serial_port = '/dev/Ultralsonic'
        # 实例化超声波设备串口
        self.ultralsonic_device = Myserial(self.serial_baud,self.serial_port)

    def run(self):
        self.RangeSignal.emit(self.median_filter()) # 发出信号

    def get_ultrasonic_data(self, commd_getRangeData='\xb2'):
        '''
            本函数得到超声波返回的数据,可以直接得到距离返回值，也可以得到传输时间返回值，默认指令采用
            返回传输延时，并串口打印
            input：
                commd_getdata:超声波模块的测试命令
            return:
                distance:返回超声波得到的16位数据
        '''
        buf_str = []
        # 得到超声波模块的数据
        ultralsonic_RangeData = []
        distance = 0
        ultralsonic_bufsize = 0
        # 得到测试命令
        self.ultr_commd_RangeTest = self.ultralsonic_commd_set + commd_getRangeData

        while ultralsonic_bufsize == 0:
            # 发送命令
            ultralsonic_bufsize = self.ultralsonic_device.send_commd(self.ultr_commd_RangeTest,'str',0.09)
            continue
        # 接收数据
        buf_str = (self.ultralsonic_device.get_RxData_org())[1]

        for i in buf_str:
            ultralsonic_RangeData.append(self.ultralsonic_device.conver_pyhex2hex(i))

        # 得到实际距离：data_H << 8 + data_L
        distance = (ultralsonic_RangeData[0] << 8) + (ultralsonic_RangeData[1])

        return distance

    def power_denoise_processing(self, commd_Denoise='\x74'):
        '''
            功能：超声波模块的降噪处理,应放在测试操作之前，且需重新上电之后才能按新配置运行
            input：commd_denoise:降噪处理的命令:

            denoise_1 --> battery_power     0x70
            denoise_2 --> USB_power         0x71
            denoise_3 --> long_USB_power    0x72
            denoise_4 --> Switching_power   0x73
            denoise_5 --> Switching_power_w 0x73
            denoise_6 --> Worse_power       0x75

        '''
        # 得到降噪命令
        self.ultr_commd_Denoise = self.ultralsonic_commd_set + commd_Denoise
        # 发送降噪命令
        self.ultralsonic_device.send_TxData(self.ultr_commd_Denoise,'str',3)

    def get_temperature_data(self, commd_getTemperData='\xca'):
        '''
            功能：得到超声波模块温度传感器18B20模块所测试的温度值
            input:commd_getTemperData :获取温度传感器的数据命令
            9位精度的温度返回值     耗时83ms        0xc9
            10位精度的温度返回值    耗时168ms       0xca
            11位精度的温度返回值    耗时315ms       0xcb
            12位精度的温度返回值    耗时610ms       0xcc
        '''
        # 声速计算公式sqrt(k * R * T)
        K = 1.4
        R = 287.15
        Temper0 = 273.15
        # 得到18B20的温度数据
        ultralsonic_TemperData = []
        ultralsonic_bufsize = 0
        temper = 0
        voice_speed = 0
        # 存放不同温度测试指令对应的延时字典
        commd_TemperDely = {'\xc9': 0.10,
                            '\xca': 0.20, '\xcb': 0.35, '\xcc': 0.65}
        # 得到温度测试指令
        self.ultr_comm_TemperTest = self.ultralsonic_commd_set + commd_getTemperData

        
        while ultralsonic_bufsize == 0:
            # 发送命令,并延时
            ultralsonic_bufsize = self.ultralsonic_device.send_commd(self.ultr_comm_TemperTest,'str',commd_TemperDely[commd_getTemperData])
            continue
        # 接收数据
        buf_str = (self.ultralsonic_device.get_RxData_org())[1]

        for i in buf_str:
            ultralsonic_TemperData.append(self.ultralsonic_device.conver_pyhex2hex(i))

        # 得到实际温度：data_H << 8 + data_L
        temper = (ultralsonic_TemperData[0] << 8) + (ultralsonic_TemperData[1])
        temper = temper * 0.0625
        # 得到声音传播速度
        voice_speed = math.sqrt(K * R * (Temper0 + temper))
        ultralsonic_bufsize = 0

        return temper, voice_speed

    def get_final_range(self, Ts, Voice_speed):
        '''
            This function can return the final range using transmission delay and voice speed
            input： 
                Ts:transmission delay
                Voice_speed:voice speed
            return:
                final_range
        '''
        self.final_range = Ts * Voice_speed / 1000.0 / 2
        return self.final_range

    def median_filter(self, Cache_num=8):
        '''
            This function is a median filter can remove some plus by accidental factor
                input: Cache_num is the scale of data buf, the bigger the Cache_num,the slower the speed
                return： return the final range of the filter
        '''
        count = 0
        i = 0
        value_buf = []
        range_sum = 0
        for count in range(0, Cache_num):
            Ts = self.get_ultrasonic_data('\xb2')
            temper, voice_speed = self.get_temperature_data('\xca')
            value_buf.append(self.get_final_range(Ts, voice_speed))

        value_buf = sorted(value_buf)
        range_sum = sum(value_buf[1: -1])
        return range_sum / 1.0 / (Cache_num - 2)

    def sliding_filter(self, Cache_num=10):
        '''
            This function is a sliding filter can remove some period noise (also you can remove some pluse 
            by accidental factor according to median filter)
                input: Cache_num is the scale of data buf, the bigger the Cache_num,the slower the speed
                return： return the final range of the filter
        '''
        buff_length = 0
        range_sum = 0
        value_buf = []
        while buff_length < Cache_num:
            Ts = self.get_ultrasonic_data('\xb2')
            temper, voice_speed = self.get_temperature_data('\xca')
            value_buf.append(self.get_final_range(Ts, voice_speed))
            buff_length = len(value_buf)
        
        # *********************
        value_buf = sorted(value_buf)
        range_sum = sum(value_buf[2:])
        # *********************
        # range_sum = sum(value_buf)
        value_buf = []
        buff_length = 0
        return range_sum / 1.0 / (Cache_num-2)
        # return range_sum / 1.0 / Cache_num


# # ******************************************************
# ultr_RangeTest_commd = '\xb2'    # 测试命令
# ultr_Denoise_commd = '\x74'      # 降噪命令
# ultr_TemperTest_commd = '\xca'   # 温度测试指令

# ultralsonic1 = ultralsonic(9600)


# while True:
#     # temper, voice_speed = ultralsonic1.get_temperature_data(
#     #     ultr_TemperTest_commd)
#     # print("温度为："),
#     # print(temper)
#     # print("声速为："),
#     # print(voice_speed)
#     # Ts = ultralsonic1.get_ultrasonic_data(ultr_RangeTest_commd)
#     # print("传输时间为："),
#     # print(Ts)
#     # print("*************************************")
#     # print("距离为："),
#     # print(ultralsonic1.get_final_range(Ts, voice_speed))
#     # # 软件延时 1s 发送测试命令
#     # time.sleep(1.5)

#     # print("***************************************")
#     # print("距离为："),
#     # print(ultralsonic1.median_filter())

    # print("距离为："),
    # print(ultralsonic1.sliding_filter(5))